﻿#include <QDebug>
#include "JZCoContext.h"
#include "JZCoCoroutine.h"

#ifdef _WIN32 

#include <Windows.h>

//JZMainContext
class JZCoMainContext
{
public:
    JZCoMainContext()
    {
        ctx = ConvertThreadToFiber(NULL);
    }

    ~JZCoMainContext()
    {
        ConvertFiberToThread();
    }

    void *ctx;
};

JZCoMainContext *createMainContext()
{
    JZCoMainContext *ctx = new JZCoMainContext();
    return ctx;
}

void destoryMainContext(JZCoMainContext *ctx)
{
    delete ctx;
}

CO_CONTEXT_HANDLE getMainContextHandle(JZCoMainContext* ctx)
{
    return ctx->ctx;
}

//JZCoContext
VOID CALLBACK FiberFunction(LPVOID lpFiberParameter);
class JZCoContext
{
public:
    JZCoContext()
    {
        task = nullptr;

        SIZE_T commit_size = 128 * 1024;
        ctx_ = CreateFiberEx(commit_size, commit_size, FIBER_FLAG_FLOAT_SWITCH, (LPFIBER_START_ROUTINE)FiberFunction, (LPVOID)this);
        Q_ASSERT(ctx_);
    }
    ~JZCoContext()
    {
        DeleteFiber(ctx_);
    }

    JZCoCoroutine *task;
    void *ctx_;
};

JZCoContext* createContext(JZCoCoroutine *co)
{
    JZCoContext *coctx = new JZCoContext();    
    coctx->task = co;
    return coctx;
}

void destoryContext(JZCoContext *ctx)
{
    delete ctx;
}

void switchCoroutine(CO_CONTEXT_HANDLE cur, CO_CONTEXT_HANDLE next)
{
    SwitchToFiber(next);
}

CO_CONTEXT_HANDLE getCoContextHandle(JZCoContext* ctx)
{
    return ctx->ctx_;
}

// 纤程执行的函数
VOID CALLBACK FiberFunction(LPVOID lpFiberParameter)
{
    JZCoContext *ctx = (JZCoContext *)lpFiberParameter;
    ctx->task->run();
    g_scheduler->endTask(ctx->task);
}

#else

#include <ucontext.h>

void FiberFunction(void *ctx);

class JZCoMainContext
{
public:    
    JZCoMainContext()
    {
        getcontext(&ctx);
    }
    
    ucontext_t ctx;
};

class JZCoContext
{
public:    
    JZCoContext()
    {
        ucontext_t *mainctx = &g_scheduler->mainContext()->ctx;
        getcontext(&ctx);
        
        ctx.uc_stack.ss_sp = stack;
        ctx.uc_stack.ss_size = sizeof(stack);
        ctx.uc_link = mainctx;
        makecontext(&ctx, (void (*)(void))FiberFunction, 1, this);
    }

    ucontext_t ctx;
    JZCoCoroutine *task;
    char stack[128 * 1024];
};


JZCoMainContext *createMainContext()
{
    JZCoMainContext *mainctx = new JZCoMainContext();
    return mainctx;
}

void destoryMainContext(JZCoMainContext *ctx)
{
    delete ctx;
}

JZCoContext* createContext(JZCoCoroutine *co)
{    
    JZCoContext *coctx = new JZCoContext();
    coctx->task = co;
    return coctx;
}

void destoryContext(JZCoContext *ctx)
{
    delete ctx;
}

void switchCoroutine(CO_CONTEXT_HANDLE cur, CO_CONTEXT_HANDLE next)
{
    swapcontext((ucontext_t*)cur, (ucontext_t*)next);
}

void FiberFunction(void *ptr)
{
    JZCoContext *ctx = (JZCoContext*)ptr;
    ctx->task->run();
    g_scheduler->endTask(ctx->task);
}

CO_CONTEXT_HANDLE getMainContextHandle(JZCoMainContext* ctx)
{
    return &ctx->ctx;
}

CO_CONTEXT_HANDLE getCoContextHandle(JZCoContext* ctx)
{
    return &ctx->ctx;
}

#endif